/*
 * === ENUNCIADO ==
 * 
 * Implementar en ASM la funci'on "dir_size" que dado un puntero a la estructura
 * directorio obtiene la suma del taman~o de todos los archivos que lo componen
 * La estructura de directorios respecta s_dir_entry y s_file_entry
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>

#define TABLE_SIZE 100

typedef enum e_entry { TYPE_FILE = 0, TYPE_DIR = 1 } entry;

typedef struct s_dir_entry {
  entry entry_type;
  char name[8+3];
  void *entrys[TABLE_SIZE];
  void *others_entrys;
} dir_entry; // __attribute__((packed))

typedef struct s_file_entry {
  entry entry_type;
  char name[8+3];
  int attr;
  int size;
  void *data;
} file_entry; // __attribute__((packed)) 

/* Dibujo del ejemplo (es bocha importante hacer dibujos (en papel es mas facil (si lo es)))

                      ______     file3
                     | dir3 |   /  file4
                     |      |--'  / file5
                     |      |----' /   ______
  ______     file0  /|      |-----'   | dir2 |
 | dir0 |   /      / |______|        /|      |---- file6
 |      |--'      /     ||          / |      |---- file7
 |      |--------'     NULL        /  |      | 
 |      |-------------------------'   |______|
 |      |----- file1                     ||
 |______|                               NULL
  __||__
 | dir1 |
 |      |--------------.   ______
 |      |               \ | dir4 |
 |      |--- file2       \|      |----- file8
 |______|                 |      |----- file9
    ||                    |      |
   NULL                   |______|
                             ||
                            NULL
*/

extern size_t dir_size(dir_entry *dir);

void complete_dir(dir_entry *dir, char* name, void* others_entrys) {
    int i;
    strcpy(dir->name, name);
    dir->entry_type = TYPE_DIR;
    dir->others_entrys = others_entrys;
    for(i=0;i<TABLE_SIZE;i++) dir->entrys[i] = NULL;
}

void complete_file(file_entry *file, char* name, int attr, int size, void* data ) {
    strcpy(file->name, name);
    file->entry_type = TYPE_FILE;
    file->attr = attr;
    file->size = size;
    file->data = data;
}

int main(int argc, char *argv[]) {
  
  printf("Antes que todo voy a ver los offsets:\n\n");
  
  printf("dir_entry size = %li\n\toffset entry_type = %li\n\toffset name = %li\
  \n\toffset entrys = %li\n\toffset others_entrys = %li\n\n",
	 sizeof(dir_entry),
	 offsetof(dir_entry,entry_type),
	 offsetof(dir_entry,name),
	 offsetof(dir_entry,entrys),
	 offsetof(dir_entry,others_entrys)
  );

  printf("file_entry size = %li\n\toffset entry_type = %li\n\toffset name = %li\
  \n\toffset attr = %li\n\toffset size = %li\n\toffset data = %li\n\n",
	 sizeof(file_entry),
	 offsetof(file_entry,entry_type),
	 offsetof(file_entry,name),
	 offsetof(file_entry,attr),
	 offsetof(file_entry,size),
	 offsetof(file_entry,data)
  );

  printf("Bueno, ahora a laburar, sumemos el total de archivos:\n\n");
  
    dir_entry *dir0, *dir1, *dir2, *dir3, *dir4;
    file_entry *file0, *file1, *file2, *file3, *file4, *file5, *file6, *file7, *file8, *file9;

    int total_size;
    size_t dir_entry_size = sizeof(dir_entry);
    size_t file_entry_size = sizeof(file_entry);

    // Allocate memory
    dir0 = malloc(dir_entry_size);
    dir1 = malloc(dir_entry_size);
    dir2 = malloc(dir_entry_size);
    dir3 = malloc(dir_entry_size);
    dir4 = malloc(dir_entry_size);
    file0 = malloc(file_entry_size);
    file1 = malloc(file_entry_size);
    file2 = malloc(file_entry_size);
    file3 = malloc(file_entry_size);
    file4 = malloc(file_entry_size);
    file5 = malloc(file_entry_size);
    file6 = malloc(file_entry_size);
    file7 = malloc(file_entry_size);
    file8 = malloc(file_entry_size);
    file9 = malloc(file_entry_size);
    
    // Initialize ROOT dir
    complete_dir(dir0, "dir0", dir1 );
    complete_dir(dir1, "dir1", NULL );
    complete_dir(dir2, "dir2", NULL );
    complete_dir(dir3, "dir3", NULL );
    complete_dir(dir4, "dir4", NULL );
    
    // Initialize files
    complete_file( file0, "file0.txt", 0, 10000, NULL );
    complete_file( file1, "file1.txt", 0,  2000, NULL );
    complete_file( file2, "file2.txt", 0,   300, NULL );
    complete_file( file3, "file3.txt", 0,    40, NULL );
    complete_file( file4, "file4.txt", 0,     5, NULL );
    complete_file( file5, "file5.txt", 0,     4, NULL );
    complete_file( file6, "file6.txt", 0,    50, NULL );
    complete_file( file7, "file7.txt", 0,   600, NULL );
    complete_file( file8, "file8.txt", 0,  7000, NULL );
    complete_file( file9, "file9.txt", 0, 80000, NULL );
    
    // Set files and dir
    dir0->entrys[45] = file0;
    dir0->entrys[50] = dir2;
    dir0->entrys[51] = dir3;
    dir0->entrys[85] = file1;
    dir1->entrys[77] = dir4;
    dir1->entrys[88] = file2;
    dir2->entrys[12] = file6;
    dir2->entrys[87] = file7;
    dir3->entrys[10] = file3;
    dir3->entrys[20] = file4;
    dir3->entrys[30] = file5;
    dir4->entrys[45] = file8;
    dir4->entrys[85] = file9;
    
    // total size
    total_size = dir_size(dir0); 
    printf("result: %d\n", total_size);

    // free willy
    free(dir0);
    free(dir1);
    free(dir2);
    free(dir3);
    free(dir4);
    free(file0);
    free(file1);
    free(file2);
    free(file3);
    free(file4);
    free(file5);
    free(file6);
    free(file7);
    free(file8);
    free(file9);
    
    return 0;
}
